#include "Client.h"
#include "../../MasLiteServer/ObjectManager.h"

int Client::Init(char* address, short port)
{
	sa.sin_family = AF_INET;
	WSADATA wsadata;
	WSAStartup(WINSOCK_VERSION, &wsadata);
	sa.sin_port = htons(port);
	clSocket = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
	if(clSocket == INVALID_SOCKET)
	{ 
		return SOCKET_ERROR;
	}
	sa.sin_addr.s_addr = inet_addr(address);
	if(connect(clSocket,(sockaddr*)&sa,sizeof(sa)) == SOCKET_ERROR)
	{
		//return ADDRESS_ERROR;
		return ADDRESS_ERROR;
	}
	unsigned long value = 1;
	if(ioctlsocket (clSocket, FIONBIO, &value) == SOCKET_ERROR)
		return SOCKET_ERROR;

	////Connect Test
	//Connected = false;
	//LoggedIn = false;
	//
	//NetworkMsg msg(_OUTPUT);

	//msg.writeInt(0);
	//msg.writeByte(CL_CONNECT);
	//SendMessage(msg);

	//unsigned int ConnectWait = 0;

	//NetworkMsg retmsg(_INPUT);
	//while(!Connected)
	//{
	//	recvfromNetMessage(clSocket,retmsg,&sa);
	//	ParseMessage(retmsg);
	//	ConnectWait++;
	//	if(ConnectWait > CONNECTTIMEOUT)
	//		return CONNECT_TIMEOUT;
	//}
	//mySequence = 0;
	commandToSend.dirty = false;
	commandToSend.Horizontal = 0;
	objectManager = ObjectManager::getInstance();
	return SUCCESS;
}

	void Client::Move(char commandType)
	{
		commandToSend.dirty = true;
		commandToSend.Horizontal = commandType;
	}
	void Client::SetAngle(float angle)
	{
		commandToSend.dirty = true;
		commandToSend.Angle = angle;
	}
	void Client::ButtonPress(char button)
	{
		commandToSend.dirty = true;
		if(button == 0)
			commandToSend.Jump = true;
		else if(button == 1)
			commandToSend.Fire = true;
	}
int Client::Connect(float red, float green, float blue)
{
	Connected = false;
	LoggedIn = false;
	
	NetworkMsg msg(_OUTPUT);

	msg.writeInt(0);
	msg.writeByte(CL_CONNECT);
	msg.writeFloat(red);
	msg.writeFloat(green);
	msg.writeFloat(blue);
	SendMessage(msg);

	unsigned int ConnectWait = 0;

	NetworkMsg retmsg(_INPUT);
	while(!Connected)
	{
		int ret = recvfromNetMessage(clSocket,retmsg,&sa);
		if(ret != -1)
			ParseMessage(retmsg);
		ConnectWait++;
		if(ConnectWait > CONNECTTIMEOUT)
			return CONNECT_TIMEOUT;
	}
	mySequence = 0;
	Running = true;
	return SUCCESS;
}
void Client::Stop()
{
	NetworkMsg msg(_OUTPUT);
	msg.writeInt(mySequence);
	msg.writeByte(CL_DISCONNECT);
	SendMessage(msg);

	closesocket(clSocket);
	WSACleanup();
}
int Client::LogIn(char* userName, char* passWord)
{
	NetworkMsg msg(_OUTPUT);
	msg.writeInt(mySequence);
	msg.writeByte(CL_LOG_IN);
	msg.write(userName,0,strlen(userName));
	msg.writeByte('\0');
	msg.write(passWord,0,strlen(passWord));
	SendMessage(msg);

	LoggedInFailed = false;
	unsigned int ConnectWait = 0;
	NetworkMsg retmsg(_INPUT);
	while(!LoggedIn)
	{
		recvfromNetMessage(clSocket,retmsg,&sa);
		ParseMessage(retmsg);
		ConnectWait++;
		if(ConnectWait > CONNECTTIMEOUT)
			//Guess the server is dead
			return SERVER_TIMEOUT;
		if(LoggedInFailed)
			return LOG_IN_FAILED;
	}
	return SUCCESS;
}
void Client::LogOut()
{
	NetworkMsg msg(_OUTPUT);
	msg.writeInt(mySequence);
	msg.writeByte(CL_LOG_OUT);
	SendMessage(msg);

	unsigned int ConnectWait = 0;
	NetworkMsg retmsg(_INPUT);
	while(LoggedIn)
	{
		recvfromNetMessage(clSocket,retmsg,&sa);
		ParseMessage(retmsg);
		ConnectWait++;
		if(ConnectWait > CONNECTTIMEOUT)
			//Guess the server is dead
			return;
	}
}
int Client::Update(float dT)
{
	if(!Running || !Connected)
		return NOT_RUNNING;
	NetworkMsg retmsg(_INPUT);
	bool hope = true;
	while(hope)
	{
	int ret = recvfromNetMessage(clSocket,retmsg,&sa);
	if(ret != -1)
		ParseMessage(retmsg);
	else
		hope = false;
	}
	serverTimer += dT;
	objectCountTimer += dT;

	CullRobots();

	//Alive
	//myTimer += dT;
	//if(myTimer > ALIVETIME)
	//{
	//	//Tell them we are alive
	//	NetworkMsg msg(_OUTPUT);
	//	msg.writeInt(mySequence);
	//	msg.writeByte(CL_ALIVE);
	//	SendMessage(msg);
	//}
	if(objectCountTimer > OBJECTCOUNTTIME)
	{
		//Tell them we are alive
		NetworkMsg msg(_OUTPUT);
		msg.writeInt(mySequence);
		msg.writeByte(CL_GET_OBJECT_COUNT);
		SendMessage(msg);
	}
	//if(serverTimer > SERVERALIVETIME)
		//return SERVER_TIMEOUT;
	if(commandToSend.dirty)
	{
		NetworkMsg msg(_OUTPUT);
		msg.writeInt(mySequence);
		msg.writeByte(CL_COMMAND);
		msg.writeByte(commandToSend.Horizontal);
		msg.writeByte(commandToSend.Jump);
		msg.writeByte(commandToSend.Fire);
		msg.writeFloat(commandToSend.Angle);
		SendMessage(msg);
		commandToSend.dirty = false;
		commandToSend.Horizontal = 0;
		commandToSend.Fire = false;
		commandToSend.Jump = false;
	}
	return SUCCESS;
}
void Client::UpdateLoop()
{
	while(Running)
	{

	}
}
void Client::ParseMessage(NetworkMsg msg)
{
	unsigned int getseq = msg.readInt();
	if(getseq < LastSeverSequence)
	{
		//Old news.  Possibly ask for catch up
		//return;
	}
	LastSeverSequence = getseq;
	char msgID = msg.readByte();
	serverTimer = 0;
	switch(msgID)
	{
	case SV_CONNECT_RECV:
		Connected = true;
		myID = msg.readByte();
		break;
	case SV_LOGGED_IN:
		LoggedIn = true;
		break;
	case SV_LOG_IN_FAIL:
		LoggedInFailed = true;
		break;
	case SV_LOGGED_OUT:
		LoggedIn = false;
		break;
	case SV_ROBOTS:
		{
			//char num = msg.readByte();
			Robot rob;
			rob.ID = msg.readInt();
			if( m_umServerToLocal.count( rob.ID ) )
			{
				//old robot
				sORobot* robo = objectManager->GetRobot( m_umServerToLocal[ rob.ID ]);

				rob.PosX = msg.readFloat();
				rob.PosY = msg.readFloat();
				rob.VelX = msg.readFloat();
				rob.VelY = msg.readFloat();
				rob.AngleGun = msg.readFloat();
				rob.Red = msg.readFloat();
				rob.Blue = msg.readFloat();
				rob.Green = msg.readFloat();

				if( robo )
				{
					robo->m_fGunAngle = rob.AngleGun;
					robo->m_fColor.cR = rob.Red;
					robo->m_fColor.cG = rob.Blue;
					robo->m_fColor.cB = rob.Green;
					robo->m_fPos.vX = rob.PosX;
					robo->m_fPos.vY = rob.PosY;
					robo->m_fVel.vX = rob.VelX;
					robo->m_fVel.vY = rob.VelY;
					robo->m_fTime = 0.0f;
				}
			}
			else
			{
				rob.PosX = msg.readFloat();
				rob.PosY = msg.readFloat();
				rob.VelX = msg.readFloat();
				rob.VelY = msg.readFloat();
				rob.AngleGun = msg.readFloat();
				rob.Red = msg.readFloat();
				rob.Blue = msg.readFloat();
				rob.Green = msg.readFloat();
				//find out if it exists
				//update if it does
				//add if it doesn't
				float2 pos;
				pos.vX = rob.PosX;
				pos.vY = rob.PosY;
				float3 col;
				col.cR = rob.Red;
				col.cB = rob.Blue;
				col.cG = rob.Green;

				int localID = objectManager->InsertRobot(pos,col);
				m_umServerToLocal[ rob.ID ] = localID;
			}
		}

		break;

	case SV_BULLETS:
		{
			BulletSpawns bill;
			bill.ID = msg.readInt();
			bill.PosX = msg.readFloat();
			bill.PosY = msg.readFloat();
			bill.VelX = msg.readFloat();
			bill.VelY = msg.readFloat();
			bill.Owner = msg.readInt();
			bill.power = msg.readFloat();
			//find out if it exists
			//update if it does
			//add if it doesn't
			float2 pos;
			pos.vX = bill.PosX;
			pos.vY = bill.PosY;
			float2 vel;
			vel.vX = bill.VelX;
			vel.vY = bill.VelY;
			objectManager->InsertBullet(bill.Owner,pos,vel,bill.power);
		}
		break;
	case SV_OBJECT_COUNT:
		{
			int count = msg.readInt();
			if(count != count)
			{
				NetworkMsg msg(_OUTPUT);
				msg.writeInt(mySequence);
				msg.writeByte(CL_GET_ALL);
				SendMessage(msg);
			}
		}
		break;
	case SV_EVERYTHING:
		{
			char robcount = msg.readByte();
			Robot rob;
			for(int i =0;i<robcount;i++)
			{
				rob.ID = msg.readInt();
				rob.PosX = msg.readFloat();
				rob.PosY = msg.readFloat();
				rob.VelX = msg.readFloat();
				rob.VelY = msg.readFloat();
				rob.AngleGun = msg.readFloat();
				rob.Red = msg.readFloat();
				rob.Blue = msg.readFloat();
				rob.Green = msg.readFloat();
				//find out if it exists
				//update if it does
				//add if it doesn't
			}
			short billcount = msg.readShort();
			BulletSpawns bill;
			for(int i =0;i<billcount;i++)
			{
				bill.ID = msg.readInt();
				bill.PosX = msg.readFloat();
				bill.PosY = msg.readFloat();
				bill.VelX = msg.readFloat();
				bill.VelY = msg.readFloat();
				bill.Owner = msg.readInt();
				//find out if it exists
				//update if it does
				//add if it doesn't
			}
		}
		break;
	default:
		//Invalid message ID
		break;
	}

}
void Client::SendMessage(NetworkMsg msg)
{
	sendtoNetMessage(clSocket,msg,&sa);
	mySequence++;
}

void Client::CullRobots()
{
	list< sORobot* >::iterator currRob = objectManager->m_liRobots.begin();
	unsigned int count = 0;
	list< int > toRemove;

	while( currRob != objectManager->m_liRobots.end() )
	{
		if( (*currRob) )
		{
			if( (*currRob)->m_fTime > 3.0f )
			{
				toRemove.push_back( count );
			}
		}
		currRob++;
		count++;
	}

	list< int >::iterator listCurr = toRemove.begin();

	while( listCurr != toRemove.end() )
	{
		objectManager->KillRobot( (*listCurr) );
		listCurr++;
	}
}